#include "CDataBuffer.hpp"
#include "CDoubleBufferQueue.hpp"
#include <queue>
#include <windows.h>

CDoubleBufferQueue::CDoubleBufferQueue()
	: m_pReceiveCriticalSection(0)
	, m_pSendCriticalSection(0)
	, m_eState(Base::STATE_OK)
{
	DBG_L1(("[%p] %s\n", this, __FUNCTION__));
	m_pReceiveCriticalSection = static_cast<void*>(new CRITICAL_SECTION);
	m_pSendCriticalSection = static_cast<void*>(new CRITICAL_SECTION);
	InitializeCriticalSection(static_cast<CRITICAL_SECTION*>(m_pReceiveCriticalSection));
	InitializeCriticalSection(static_cast<CRITICAL_SECTION*>(m_pSendCriticalSection));
}

CDoubleBufferQueue::~CDoubleBufferQueue()
{
	DBG_L1(("[%p] %s\n", this, __FUNCTION__));
	if (m_pReceiveCriticalSection != 0)
	{
		DeleteCriticalSection(static_cast<CRITICAL_SECTION*>(m_pReceiveCriticalSection));
		delete static_cast<CRITICAL_SECTION*>(m_pReceiveCriticalSection);
	}
	if (m_pSendCriticalSection != 0)
	{
		DeleteCriticalSection(static_cast<CRITICAL_SECTION*>(m_pSendCriticalSection));
		delete static_cast<CRITICAL_SECTION*>(m_pSendCriticalSection);
	}
}

void CDoubleBufferQueue::PushToReceiveQueue(CDataBuffer* buffer)
{
	DBG_L3(("[%p] %s\n", this, __FUNCTION__));
	EnterCriticalSection(static_cast<CRITICAL_SECTION*>(m_pReceiveCriticalSection));
	m_qReceiveQueue.push(*buffer);
	LeaveCriticalSection(static_cast<CRITICAL_SECTION*>(m_pReceiveCriticalSection));
}

void CDoubleBufferQueue::PushToSendQueue(CDataBuffer* buffer)
{
	DBG_L3(("[%p] %s\n", this, __FUNCTION__));
	EnterCriticalSection(static_cast<CRITICAL_SECTION*>(m_pSendCriticalSection));
	m_qSendQueue.push(*buffer);
	LeaveCriticalSection(static_cast<CRITICAL_SECTION*>(m_pSendCriticalSection));
}

/*void CDoubleBufferQueue::PickFirstFromReceiveQueue(CDataBuffer& buffer)
{
	DBG_L3(("[%p] %s\n", this, __FUNCTION__));
	EnterCriticalSection(static_cast<CRITICAL_SECTION*>(m_pReceiveCriticalSection));
	if (m_qReceiveQueue.size() != 0)
	{
		buffer.append(const_cast<UChr*>(m_qReceiveQueue.front().data()), m_qReceiveQueue.front().size());
	}
	LeaveCriticalSection(static_cast<CRITICAL_SECTION*>(m_pReceiveCriticalSection));
}

void CDoubleBufferQueue::PickFirstFromSendQueue(CDataBuffer& buffer)
{
	DBG_L3(("[%p] %s\n", this, __FUNCTION__));
	EnterCriticalSection(static_cast<CRITICAL_SECTION*>(m_pSendCriticalSection));
	if (m_qSendQueue.size() != 0)
	{
		buffer.append(const_cast<UChr*>(m_qSendQueue.front().data()), m_qSendQueue.front().size());
	}
	LeaveCriticalSection(static_cast<CRITICAL_SECTION*>(m_pSendCriticalSection));
}*/

void CDoubleBufferQueue::PopFromReceiveQueue(CDataBuffer& buffer)
{
	DBG_L3(("[%p] %s\n", this, __FUNCTION__));
	EnterCriticalSection(static_cast<CRITICAL_SECTION*>(m_pReceiveCriticalSection));
	if (m_qReceiveQueue.size() != 0)
	{
		buffer.append(const_cast<UChr*>(m_qReceiveQueue.front().data()), m_qReceiveQueue.front().size());
		m_qReceiveQueue.pop();
	}
	LeaveCriticalSection(static_cast<CRITICAL_SECTION*>(m_pReceiveCriticalSection));
}

void CDoubleBufferQueue::PopFromSendQueue(CDataBuffer& buffer)
{
	DBG_L3(("[%p] %s\n", this, __FUNCTION__));
	EnterCriticalSection(static_cast<CRITICAL_SECTION*>(m_pSendCriticalSection));
	if (m_qSendQueue.size() != 0)
	{
		buffer.append(const_cast<UChr*>(m_qSendQueue.front().data()), m_qSendQueue.front().size());
		m_qSendQueue.pop();
	}
	LeaveCriticalSection(static_cast<CRITICAL_SECTION*>(m_pSendCriticalSection));
}

void CDoubleBufferQueue::setState(Base::eState state)
{
	m_eState = state;
}

Base::eState CDoubleBufferQueue::getState() const
{
	return m_eState;
}

UInt32 CDoubleBufferQueue::getReceiveQueueSize()
{
	DBG_L4(("[%p] %s\n", this, __FUNCTION__));
	EnterCriticalSection(static_cast<CRITICAL_SECTION*>(m_pReceiveCriticalSection));
	UInt32 size = m_qReceiveQueue.size();
	LeaveCriticalSection(static_cast<CRITICAL_SECTION*>(m_pReceiveCriticalSection));
	return size;
}

UInt32 CDoubleBufferQueue::getSendQueueSize()
{
	DBG_L4(("[%p] %s\n", this, __FUNCTION__));
	EnterCriticalSection(static_cast<CRITICAL_SECTION*>(m_pSendCriticalSection));
	UInt32 size = m_qSendQueue.size();
	LeaveCriticalSection(static_cast<CRITICAL_SECTION*>(m_pSendCriticalSection));
	return size;
}
